package com.zysdev.videochart

import android.media.MediaCodec
import android.media.MediaCodecInfo
import android.media.MediaFormat
import android.util.Log
import java.lang.Exception
import java.nio.ByteBuffer
import java.util.*
import kotlin.experimental.and

class EncodecPushLiveH265(
    val socketCallback: SocketLive.SocketCallback,
    val width: Int,
    val height: Int
) {
    private var mediaCodec: MediaCodec? = null

    private var socketLive: SocketLive? = null

    private var nv12: ByteArray? = null

    //    旋转之后的yuv数据
    private var yuv: ByteArray? = null
    private val NAL_I = 19
    private val NAL_VPS = 32
    private var vps_sps_pps_buf: ByteArray? = null

    //帧顺序
    private var frameIndex = 0L

    init {
        this.socketLive = SocketLive(socketCallback)
        //        建立链接
        socketLive!!.start()
    }


    fun startLive() {
        //        实例化编码器
        //创建对应编码器
        try {
            mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC)
            //因摄像头是横着的，编码时的宽高要对换
            val format =
                MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, height, width)
            format.setInteger(MediaFormat.KEY_FRAME_RATE, 15)
            format.setInteger(MediaFormat.KEY_BIT_RATE, width * height)
            format.setInteger(
                MediaFormat.KEY_COLOR_FORMAT,
                MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible
            )
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5) //IDR帧刷新时间

            mediaCodec!!.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
            mediaCodec!!.start()

            //yuv的长度=width * height * 3 / 2
            val bufferLength = width * height * 3 / 2

            nv12 = ByteArray(bufferLength)
            yuv = ByteArray(bufferLength)

        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun encodeFrame(input: ByteArray?) {

        if (input?.isEmpty() == true) {
            return
        }
        //横着的yuv（NV21）原始数据
        //先将NV21转换为NV12
        nv12 = YuvUtils.nv21toNV12(input)
        //旋转NV12(Y420)数据
        YuvUtils.portraitData2Raw(nv12, yuv, width, height)
        //编码

        val inputBufferIndex = mediaCodec!!.dequeueInputBuffer(100000)

        //放yuv原始数据
        if (inputBufferIndex >= 0) {
            val bufferArray = mediaCodec!!.getInputBuffer(inputBufferIndex)
            bufferArray?.clear()
            bufferArray?.put(yuv!!)
            val pts = computePresentationTime(frameIndex)
            mediaCodec!!.queueInputBuffer(inputBufferIndex, 0, yuv!!.size, pts, 0)
            frameIndex++
        }
        //取编码后数据
        val bufferInfo = MediaCodec.BufferInfo()

        var outputBufferIndex = mediaCodec!!.dequeueOutputBuffer(bufferInfo, 100000)

        while (outputBufferIndex >= 0) {
            val bufferArray = mediaCodec!!.getOutputBuffer(outputBufferIndex)
            //找到vps_sps_pps,存起来,帧数据发送
            dealFrame(bufferArray!!, bufferInfo)

            mediaCodec!!.releaseOutputBuffer(outputBufferIndex, false)
            outputBufferIndex = mediaCodec!!.dequeueOutputBuffer(bufferInfo, 0)
        }




    }

    private fun dealFrame(outBufferArray: ByteBuffer, bufferInfo: MediaCodec.BufferInfo) {

        var offset = 4
        if (outBufferArray.get(2) == 0x01.toByte()) {
            offset = 3
        }
        val type: Int = (outBufferArray.get(offset) and 0x7E).toInt().shr(1)
        Log.e("---", "---NAL_type=$type")
        when (type) {
            NAL_VPS -> {//vps_sps_pps数据存起来
                vps_sps_pps_buf = ByteArray(bufferInfo.size)
                outBufferArray.get(vps_sps_pps_buf)
            }
            NAL_I -> {//I帧，在前面加上vps_sps_pps_buf
                val bytes = ByteArray(bufferInfo.size)
                outBufferArray.get(bytes)
                val newBuf = ByteArray(vps_sps_pps_buf!!.size + bytes.size)
                System.arraycopy(vps_sps_pps_buf, 0, newBuf, 0, vps_sps_pps_buf!!.size)
                System.arraycopy(bytes, 0, newBuf, vps_sps_pps_buf!!.size, bytes.size)
                socketLive!!.sendData(newBuf)//传出
            }
            else -> {//P、B帧
                val bytes = ByteArray(bufferInfo.size)
                outBufferArray.get(bytes)
                socketLive!!.sendData(bytes)//传出
                Log.v("---", "视频数据  " + Arrays.toString(bytes))
            }
        }
    }


    //pts 时间
    private fun computePresentationTime(frameIndex: Long): Long {
        return 132 + frameIndex * 1000000 / 15
    }

}